/**
Copyright 2011 Steven Moxley

This file is part of Joggle.

Joggle is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Joggle is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Joggle.  If not, see <http://www.gnu.org/licenses/>.
*/
package edu.gwu.cs.joggle;

import java.util.ArrayList;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.almworks.sqlite4java.SQLiteException;

/**
 * @author      Steven Moxley <steven.moxley@gmail.com>
 * @version     1               
 * @since       2011-12-20
 */
public class Auditor extends User {
	
	protected ArrayList<Game> authorizedGames;		// filenames of logs of game states this auditor is authorized to audit
	protected ArrayList<Player> authorizedPlayers;	// users this auditor is authorized to audit
	protected Server server;						// the Server where this Auditor's account is valid
	protected Boolean newAccount;
	
	/**
	 * Updates and gets the list of historic game logs this Auditor is authorized to audit
	 * @return ArrayList<String> The ArrayList of logs this Auditor is authorized to audit
	 */
	protected ArrayList<Game> getAuthorizedGames() {
		// do SQL query on Server to get up-to-date list of historic game logs this Auditor is authorized to audit (to prevent TOCTOU)
		
		return authorizedGames;
	}
	
    /** 
     * Returns a list of historic game logs this Auditor is authroized to audit
     * @return String
     */
	protected String getAuthorizedGamesAsString() {
		getAuthorizedGames();
		String result = "";
		for(Game g : authorizedGames) {
			result += g.getSeed() + "#";
		}
		return result;
	}
	
	/**
	 * @param g The game to be added to this Auditor's ACL
	 */
	protected void addAuthorizedGame(Game g) {
		authorizedGames.add(g);
    server.setAuditorGames(this);
	}
	
	/**
	 * @param g The game to be removed from this Auditor's ACL
	 */
	protected void removeAuthorizedGame(Game g) {
		authorizedGames.remove(g);
    server.setAuditorGames(this);
	}
	
	/**
	 * @return The ArrayList of Players this Auditor is authorized to audit
	 * @return ArrayList<Player>
	 */
	protected ArrayList<Player> getAuthorizedPlayers() {
		return authorizedPlayers;
	}

    /**
     * Returns a String of Players this Auditor is authorized to audit
     * @return String
     */
	
	protected String getAuthorizedPlayersAsString() {
		String result = "";
		for(Player p : authorizedPlayers) {
			result += p.getUserName() + "#";
		}
		return result;
	}
	
	/**
	 * @param p The Player to be added to this Auditor's ACL
	 */
	protected void addAuthorizedPlayer(Player p) {
		authorizedPlayers.add(p);
    server.setAuditorPlayers(this);
	}
	
	/**
	 * @param p The Player to be removed from this Auditor's ACL
	 */
	protected void removeAuthorizedPlayer(Player p) {
		authorizedPlayers.remove(p);
    server.setAuditorPlayers(this);
	}
	
	/**
	 * Review the log file of a game and make a determination on whether to accept the results of the game (update the relevant players' point values with the point totals referenced in the log), or reject the results of the game (do nothing as the server's validation of a game defaults to not altering the player point totals if the game is deemed to be in need of auditing)
	 * @param g The Game to be reviewed/audited/analyzed somehow by this Auditor
	 * @throws IllegalAccessException
	 */
	protected void reviewGame(Game g) throws IllegalAccessException {
	    updateUserLog("reviewed game: " + g + ".\n");
		getAuthorizedGames();
		if(authorizedGames.contains(g)) {
			// open file, print contents, etc.
			System.out.println("Game created by " + g.getOwner().getUserName() + " with seed " + g.getSeed() + " was played by " + g.getNumPlayers() + " player(s).");
			System.out.println("Do you accept this game as valid? (yes / no, then enter)");
			BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
			String response = null;
			try {
			    response = br.readLine();
			} catch (IOException e) {
			    System.out.println("Error reading string");
			    System.exit(1);
			}
			if (response.equals("yes")) {
			    //take string formed by reading the logfile, 
			    //break it up using "\n" as the delimiter (this should 
			    //work), and feed the result into a String[] named str; 
			    //running this on that String[] should give
			    //you two arrays, one with the player names and one with 
			    //the associated points (names[0] corresponds
			    //with points[0], //etc.). Then you just need to iterate 
			    //through those in unison to update the user
			    //points, assuming you figure out how to solve the 
			    //problem of not having access to the server
			    //function setUserPoints
			    String[] str = new String[0];
			    Pattern pattern = Pattern.compile("Player (\\w) should be awarded (\\d)+ points for the game");
			    Matcher matcher = pattern.matcher("");
			    ArrayList<String> matches = new ArrayList<String>();
			    
			    for(int i = 0; i < str.length; i++) {
				matcher.reset(str[i]);
				if(matcher.find()) {
				    matches.add(str[i]);
				    //System.out.println("found one");
				}
				else {
				    //System.out.println("didn't match");
				}
			    }
			    
			    int[] pts = new int[matches.size()];
			    String[] names = new String[matches.size()];
			    int x = 0;
			    
			    for(String list : matches) {
				String[] instr = list.split(" ");
				names[x] = instr[1];
				pts[x] = Integer.parseInt(instr[4]);
				x++;
			    }
			    
                            removeAuthorizedGame(g);
			} else if (response.equals("no")) {
			    System.out.println("Well then, something must be done about it!");
			} else {
			    System.out.println("please type \"yes\" or \"no\" then enter");
			}
		} else {
			throw new IllegalAccessException("You are not authorized to audit that game!");
		}
	}
	
	/**
	 * Review the log file associated with a given user and make a determination on whether to recommend action be taken against the user by the administrator
	 * @param p The Player to be reviewed/audited/analyzed somehow by this Auditor
	 * @throws IllegalAccessException
	 */
	protected void reviewPlayer(Player p) throws IllegalAccessException {
	    updateUserLog("reviewed Player " + p.getUserName() + "'s profile.\n");
		getAuthorizedPlayers();
		if(authorizedPlayers.contains(p)) {
			p.getProfile(this);
			System.out.println("Is this an acceptable profile? (yes / no, then enter)");
			BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
			String response = null;
			try {
			    response = br.readLine();
			} catch (IOException e) {
			    System.out.println("Error reading string");
			    System.exit(1);
			}
			if (response.equals("yes")) {
			    removeAuthorizedPlayer(p);
			} else if (response.equals("no")) {
			    System.out.println("Well then, something must be done about it!");
			} else {
			    System.out.println("please type \"yes\" or \"no\" then enter");
			}
		} else {
			throw new IllegalAccessException("You are not authorized to audit that log!");
		}
	}

    /**
     * Returns the string representation of this Auditor
     * @return String
     */
	
	public String toString() {
		return "The Auditor " + firstName + " " + lastName + " (" + userName + ") is authorized to audit " + authorizedGames.size() + " logs and " + authorizedPlayers.size() + " players.";
	}

	/**
	 * @param fName The Auditor's real first name
	 * @param lName The Auditor's real last name
	 * @param uName The Auditor's Joggle username
	 * @param email The Auditor's preferred email address
	 * @param logs The ArrayList of logs (w/ game states? server events?) the Auditor is authorized to read (write or modify?)
	 * @param players The ArrayList of Players' logs (w/ login attempts? profile updates? friends list?)
	 * @param s The Server where this Auditor is authorized to perform audits
	 * @param a The Administrator creating this Auditor
	 * @return void
	 * @throws SQLiteException 
	 */
	public Auditor(String fName, String lName, String uName, String email, String pwd, ArrayList<Game> games, ArrayList<Player> players, Server s, Administrator a, Boolean newAcct) {
		super(fName, lName, uName, email, pwd);
		authorizedGames = games;
		authorizedPlayers = players;
		server = s;
		newAccount = newAcct;
		
		if(newAccount) {
			try {
				s.addAuditor(this, a);
			} catch (SQLiteException e) {
				e.printStackTrace();
			}
		}
	}
}
